package sdk

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"aifuture.cloud/helper"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)

type RequestSigner struct {
	AccessKeyId          string
	AccessKeySecret      string
	Endpoint             string
	Params               map[string]string
	Logger               *log.Logger // 添加一个日志记录器
	Timeout              time.Duration
	RetryCount           int
	FallbackData         []byte                                             // 静态数据作为熔断处理的回退
	Interceptor          func([]byte) []byte                                // 拦截器函数
	RedirectFunc         func(req *http.Request, via []*http.Request) error //重定向函数
	ResourceOwnerAccount string                                             //账号
	Port                 int                                                //端口号
}

func NewRequestSigner(accessKeyId, accessKeySecret, endpoint string, port int, logger *log.Logger, ResourceOwnerAccount string) *RequestSigner {
	return &RequestSigner{
		AccessKeyId:          accessKeyId,
		AccessKeySecret:      accessKeySecret,
		Endpoint:             endpoint,
		Params:               make(map[string]string),
		Logger:               logger,
		Timeout:              10 * time.Second, // 设置超时时间为10秒
		RetryCount:           3,
		ResourceOwnerAccount: ResourceOwnerAccount,
		Port:                 port,
	}
}

func (rs *RequestSigner) AddParam(key, value string) {
	rs.Params[key] = value
}

func (rs *RequestSigner) percentEncode(encodeStr string) string {
	encodeStr = fmt.Sprint(encodeStr)
	if utf8.RuneCountInString(encodeStr) == len(encodeStr) {
		return url.QueryEscape(encodeStr)
	}
	if utf8.RuneCountInString(encodeStr) > len(encodeStr) {
		res := url.QueryEscape(encodeStr)
		res = strings.ReplaceAll(res, "+", "%20")
		res = strings.ReplaceAll(res, "*", "%2A")
		res = strings.ReplaceAll(res, "%7E", "~")
		return res
	}
	return ""
}

//func (rs *RequestSigner) percentEncode(value string) string {
//	// 使用url.QueryEscape进行URL编码
//	encoded := url.QueryEscape(value)
//	// 按照规则将编码后的字符进行替换
//	encoded = strings.Replace(encoded, "+", "%20", -1)
//	encoded = strings.Replace(encoded, "*", "%2A", -1)
//	encoded = strings.Replace(encoded, "%7E", "~", -1)
//	return encoded
//}

func (rs *RequestSigner) constructCanonicalQueryString() string {
	var paramList []string

	// 按字典顺序对参数名称进行排序
	keys := make([]string, 0, len(rs.Params))
	for key := range rs.Params {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	// 构建参数键值对
	for _, key := range keys {
		param := key + "=" + rs.percentEncode(rs.Params[key])
		paramList = append(paramList, param)
	}

	// 使用"&"连接参数键值对
	return strings.Join(paramList, "&")
}

func (rs *RequestSigner) constructStringToSign(httpMethod, canonicalQueryString string) string {
	return httpMethod + "&%2F&" + rs.percentEncode(canonicalQueryString)
}

func (rs *RequestSigner) calculateSignature(stringToSign string) string {
	key := rs.AccessKeySecret + "&"
	h := hmac.New(sha1.New, []byte(key))
	h.Write([]byte(stringToSign))
	signatureBytes := h.Sum(nil)
	return base64.StdEncoding.EncodeToString(signatureBytes)
}

func (rs *RequestSigner) GetRequestURL() string {
	rs.setInternalParams()
	// 构建规范化请求字符串
	canonicalQueryString := rs.constructCanonicalQueryString()

	// 构建签名字符串
	stringToSign := rs.constructStringToSign("GET", canonicalQueryString)

	// 计算签名
	signature := rs.calculateSignature(stringToSign)

	// 添加签名到参数
	rs.Params["Signature"] = signature

	// 构建最终请求URL
	var paramList []string
	for key, _ := range rs.Params {
		param := key + "=" + rs.percentEncode(rs.Params[key])
		paramList = append(paramList, param)
	}
	requestURL := rs.Endpoint + ":" + strconv.Itoa(rs.Port) + "/?" + strings.Join(paramList, "&")

	return requestURL
}

// 设置内部固定参数
func (rs *RequestSigner) setInternalParams() {
	rs.Params["Format"] = "JSON"
	rs.Params["SignatureMethod"] = "HMAC-SHA1"
	rs.Params["SignatureVersion"] = "1.0"
	rs.Params["TimeStamp"] = time.Now().UTC().Format("2006-01-02T15:04:05Z")
	rs.Params["Version"] = time.Now().UTC().Format("2006-01-02")
	rs.Params["SignatureNonce"] = helper.GetUUID()
	rs.Params["ResourceOwnerAccount"] = rs.ResourceOwnerAccount
	rs.Params["AccessKeyId"] = rs.AccessKeyId
}

//内部默认集成的 重定向检测函数
func (rs *RequestSigner) defaultCheckRedirectFunc(req *http.Request, via []*http.Request) error {
	// 在这个函数中，你可以自定义处理重定向的逻辑
	// 例如，你可以检查重定向次数，修改请求头等

	// 示例：打印重定向信息
	fmt.Printf("重定向：[%d] %s\n", len(via), req.URL)

	// 如果需要中止重定向，可以返回一个错误
	if len(via) >= 10 {
		return fmt.Errorf("太多重定向")
	}

	// 返回 nil 表示继续执行重定向
	return nil
}
func (rs *RequestSigner) Request() ([]byte, error) {
	var err error
	var response []byte
	httpUrl := rs.GetRequestURL()
	for i := 0; i < rs.RetryCount; i++ {
		// 记录请求信息到日志
		rs.Logger.Printf("发起请求：%s\n", httpUrl)

		// 创建HTTP客户端
		client := &http.Client{
			Timeout:       rs.Timeout,
			CheckRedirect: rs.defaultCheckRedirectFunc,
		}
		//如果重定向函数存在则进行重定向函数的检测
		if rs.RedirectFunc != nil {
			client.CheckRedirect = rs.RedirectFunc
		}

		// 发起HTTP GET请求
		resp, err := client.Get(httpUrl)
		if err != nil {
			rs.Logger.Printf("发起请求时出错：%v\n", err)
			if i < rs.RetryCount-1 {
				rs.Logger.Printf("重试 #%d\n", i+1)
				continue
			}
			// 熔断处理：返回配置的静态数据
			rs.Logger.Println("执行熔断处理，返回静态数据")
			return rs.FallbackData, nil
		}

		// 读取响应内容
		response, err = ioutil.ReadAll(resp.Body)
		defer resp.Body.Close()
		if err != nil {
			rs.Logger.Printf("读取响应内容时出错：%v\n", err)
			if i < rs.RetryCount-1 {
				rs.Logger.Printf("重试 #%d\n", i+1)
				continue
			}
			// 熔断处理：返回配置的静态数据
			rs.Logger.Println("执行熔断处理，返回静态数据")
			return rs.FallbackData, nil
		}

		// 请求成功，退出循环
		break
	}
	// 调用拦截器处理响应数据
	if rs.Interceptor != nil {
		response = rs.Interceptor(response)
	}
	return response, err
}
